package io.noties.markwon.base.image.size

import android.graphics.Rect
import io.noties.markwon.base.image.AsyncDrawable
import io.noties.markwon.base.image.ImageSize

/**
 * @since 1.0.1
 */
open class ImageSizeResolverDef : ImageSizeResolver {
    override fun resolveImageSize(drawable: AsyncDrawable): Rect {
        return resolveImageSize(
            drawable.imageSize,
            drawable.resultDrawable!!.bounds,
            drawable.lastKnownCanvasWidth,
            drawable.lastKnowTextSize
        )
    }

    protected open fun resolveImageSize(
        imageSize: ImageSize?,
        imageBounds: Rect,
        canvasWidth: Int,
        textSize: Float
    ): Rect {
        if (imageSize == null) {
            // @since 2.0.0 post process bounds to fit canvasWidth (previously was inside AsyncDrawable)
            //      must be applied only if imageSize is null
            val w = imageBounds.width()
            return if (w > canvasWidth) {
                val reduceRatio = w.toFloat() / canvasWidth
                Rect(
                    0,
                    0,
                    canvasWidth, (imageBounds.height() / reduceRatio + .5f).toInt()
                )
            } else {
                imageBounds
            }
        }
        val rect: Rect
        val width = imageSize.width
        val height = imageSize.height
        val imageWidth = imageBounds.width()
        val imageHeight = imageBounds.height()
        val ratio = imageWidth.toFloat() / imageHeight
        if (width != null) {
            val w: Int = if (UNIT_PERCENT == width.unit) {
                (canvasWidth * (width.value / 100f) + .5f).toInt()
            } else {
                resolveAbsolute(width, imageWidth, textSize)
            }
            val h = if (height == null || UNIT_PERCENT == height.unit) {
                (w / ratio + .5f).toInt()
            } else {
                resolveAbsolute(height, imageHeight, textSize)
            }
            rect = Rect(0, 0, w, h)
        } else if (height != null) {
            rect = if (UNIT_PERCENT != height.unit) {
                val h = resolveAbsolute(height, imageHeight, textSize)
                val w = (h * ratio + .5f).toInt()
                Rect(0, 0, w, h)
            } else {
                imageBounds
            }
        } else {
            rect = imageBounds
        }
        return rect
    }

    protected fun resolveAbsolute(
        dimension: ImageSize.Dimension,
        original: Int,
        textSize: Float
    ): Int {

        return if (UNIT_EM == dimension.unit) {
            (dimension.value * textSize + .5f).toInt()
        } else {
            (dimension.value + .5f).toInt()
        }
    }

    companion object {
        // we track these two, others are considered to be pixels
         const val UNIT_PERCENT = "%"
         const val UNIT_EM = "em"
    }
}